package org.demo.es.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import org.demo.es.service.SearchService;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.FieldSort;
import co.elastic.clients.elasticsearch._types.SortOptions;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.query_dsl.MatchQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

/**
 * SearchService实现类
 * 用于定义ElasticSearch的文档的查询操作
 * @author moxiaoli
 */
@Slf4j
@Service
public class SearchServiceImpl implements SearchService {

    @Autowired
    private ElasticsearchClient elasticsearchClient;

    @Override
    public <T> List<T> searchDocumentByKeyword(String index, String keyword, Class<T> clazz) {
        try {
            SearchResponse<T> response = elasticsearchClient.search(s -> s
                            .index(index)
                            .query(
                                    q -> q
                                    // 模糊查询，可以使用分词器
                                    .match(t -> t
                                            .field("title")
                                            .query(keyword)
                                    )
                                    // 精确查询，不使用分词器
//                                    .term(t -> t
//                                            .field("name")
//                                            .value(keyword)
//                                    )
                            ),
                    clazz
            );
            List<Hit<T>> hits = response.hits().hits();
            return hits.stream().map(Hit::source).collect(Collectors.toList());
        }catch (Exception e){
            log.error("索引查询失败：{}", e.getMessage());
        }
        return null;
    }

    @Override
    public <T> List<T> searchDocument(String index, String query, Class<T> clazz) {
        JSONObject map = JSON.parseObject(query);
        // 构造查询条件
        List<Query> queryList = map.entrySet().stream().map(entry -> MatchQuery.of(
                m->m.field(entry.getKey()).query(entry.getValue().toString())
        )._toQuery()).collect(Collectors.toList());

//        Query query1 = TermsQuery.of(
//                m->m.field("name").terms(new TermsQueryField.Builder().value(null).build())
//        )._toQuery();

        log.info("查询条件：{}", queryList);

//         以下代码等同于上面的代码
//         List<Query> queryList = new ArrayList<>();
//        map.forEach((k, v) -> {
//            Query query1 = MatchQuery.of(
//                    m->m.field(k).query(v.toString())
//            )._toQuery();
//            queryList.add(query1);
//        });

        try {
            SearchResponse<T> response = elasticsearchClient.search(s -> s
                            .index(index)
                            .query(
                                    q -> q.bool(b -> b.must(queryList)) // 多条件查询
                            ),
                    clazz
            );
            List<Hit<T>> hits = response.hits().hits();
            return hits.stream().map(Hit::source).collect(Collectors.toList());
        }catch (Exception e){
            log.error("索引查询失败：{}", e.getMessage());
        }
        return null;
    }

    @Override
    public <T> List<T> searchDocument(String index, String query, int from, int size, Class<T> clazz) {
        JSONObject map = JSON.parseObject(query);
        // 构造查询条件
        List<Query> queryList = map.entrySet().stream().map(entry -> MatchQuery.of(
                m->m.field(entry.getKey()).query(entry.getValue().toString())
        )._toQuery()).collect(Collectors.toList());

        try {
            SearchResponse<T> response = elasticsearchClient.search(s -> s
                            .index(index)
                            .query(
                                    q -> q.bool(b -> b.must(queryList)) // 多条件查询
                            )
                            .from(from)
                            .size(size)
                    , clazz
            );
            List<Hit<T>> hits = response.hits().hits();
            return hits.stream().map(Hit::source).collect(Collectors.toList());
        }catch (Exception e){
            log.error("索引查询失败：{}", e.getMessage());
        }
        return null;
    }

    @Override
    public <T> List<T> searchDocument(String index, String query, String sort, Class<T> clazz) {
        JSONObject map = JSON.parseObject(query);
        // 构造查询条件
        List<Query> queryList = map.entrySet().stream().map(entry -> MatchQuery.of(
                m->m.field(entry.getKey()).query(entry.getValue().toString())
        )._toQuery()).collect(Collectors.toList());
        String[] sortArr = sort.replace("\\{","").replace("\\}","").split(":");
        log.info("排序字段：{}", sortArr[0]);
        // 构造排序条件
        SortOptions sortOptions = SortOptions.of(s -> s
                .field(FieldSort.of(f->f
                        .field(sortArr[0]) // 获取排序字段
                        .order("desc".equals(sortArr[1]) ? SortOrder.Desc : SortOrder.Asc))) // 获取排序方式
                );
        try {
            SearchResponse<T> response = elasticsearchClient.search(s -> s
                            .index(index)
                            .query(
                                    q -> q.bool(b -> b.must(queryList)) // 多条件查询
                            )
                            .sort(sortOptions)
                    , clazz
            );
            List<Hit<T>> hits = response.hits().hits();
            return hits.stream().map(Hit::source).collect(Collectors.toList());
        }catch (Exception e){
            log.error("索引查询失败：{}", e.getMessage());
        }
        return null;
    }

    @Override
    public <T> List<T> searchDocument(String index, String query, String sort, int from, int size, Class<T> clazz) {
        try {
            SearchResponse<T> response = elasticsearchClient.search(s -> s
                            .index(index)
                            .q(query) // 查询条件
                            .from(from)
                            .size(size)
                    , clazz
            );
            List<Hit<T>> hits = response.hits().hits();
            return hits.stream().map(Hit::source).collect(Collectors.toList());
        }catch (Exception e){
            log.error("索引查询失败：{}", e.getMessage());
        }
        return null;
    }

    @Override
    public <T> List<T> searchDocument(String index, String query, String sort, String highlight, Class<T> clazz) {
        return null;
    }

    @Override
    public <T> List<T> searchDocument(String index, String query, String sort, String highlight, int from, int size, Class<T> clazz) {
        return null;
    }
}
